#include <sys/time.h>
#include <cstdio>
#include <string>
#include "timer.h"

double Timer::communication_elapsed_ = 0.0;
double Timer::last_communication_begin_time_ = 0.0;
double Timer::sync_elapsed_ = 0.0;
double Timer::last_sync_begin_time_ = 0.0;


Timer::Timer() {
  communication_ = 0.0;
  computation_ = 0.0;
  total_ = 0.0;
  sync_ = 0.0;
}

double Timer::GetCurrentTime() {
  struct timeval start;
  gettimeofday(&start, NULL);
  return  static_cast<double>(start.tv_sec) +
          static_cast<double>(start.tv_usec)/1000000;
}

void Timer::Start() {
  start_ = GetCurrentTime();
  communication_start_ = communication_elapsed_;
  sync_start_ = sync_elapsed_;
}

void Timer::Stop() {
  double sync_add  = sync_elapsed_ - sync_start_;
  double commu_add = communication_elapsed_ - communication_start_;

  total_         += GetCurrentTime() - start_;
  sync_          += sync_add;
  communication_ += commu_add;
  computation_   = total_ - communication_ - sync_;
}

void Timer::CommunicationStart() {
  last_communication_begin_time_ = GetCurrentTime();
}

void Timer::CommunicationStop() {
  communication_elapsed_ += GetCurrentTime() - last_communication_begin_time_;
}

void Timer::SynchronizationStart() {
  last_sync_begin_time_ = GetCurrentTime();
}

void Timer::SynchronizationStop() {
  sync_elapsed_ += GetCurrentTime() - last_sync_begin_time_;
}

void Timer::Add(const Timer &t) {
  total_         += t.total();
  sync_          += t.sync();
  communication_ += t.communication();
  computation_   += t.computation();
}

void Timer::Minus(const Timer &t) {
  total_         -= t.total();
  sync_          -= t.sync();
  communication_ -= t.communication();
  computation_   -= t.computation();
}

string Timer::PrintInfo() const {
  char sz_line[256];
  snprintf(sz_line, sizeof(sz_line),
           "%e [Calc: %e][Commu: %e][Sync: %e]",
           total_, computation_, communication_, sync_);
  return sz_line;
}
